// Copyright (c) 2011 Blue Onion Software, All rights reserved
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

namespace BlueOnionSoftware.Bloget
{
    internal class BlogView : View
    {
        private bool _disposed;
        private readonly TextBox _commentName = new TextBox();
        private readonly TextBox _commentEmail = new TextBox();
        private readonly TextBox _commentTitle = new TextBox();
        private readonly TextBox _commentText = new TextBox();

        private const string CommentThrottle = "bloget_commentThrottle";

        internal BlogView(BlogetBlog blogetBlog)
            : base(blogetBlog)
        {
            _commentName.ID = "commentName";
            _commentEmail.ID = "commentEmail";
            _commentTitle.ID = "commentTitle";
            _commentText.ID = "commentText";

            if (Bloget.Page.Header != null && Bloget.Blog.EnableRealSimpleDiscovery)
            {
                var link = new HtmlLink();
                link.Attributes.Add("rel", "EditURI");
                link.Attributes.Add("type", "application/rsd+xml");
                link.Attributes.Add("title", "RSD");
                link.Attributes.Add("href", Bloget.RpcServiceUrl());
                Bloget.Page.Header.Controls.Add(link);
            }
        }

        protected override void Dispose(bool managed)
        {
            try
            {
                if (_disposed == false)
                {
                    _disposed = true;

                    if (managed)
                    {
                        _commentName.Dispose();
                        _commentEmail.Dispose();
                        _commentTitle.Dispose();
                        _commentText.Dispose();
                    }
                }
            }

            finally
            {
                base.Dispose(managed);
            }
        }

        protected override string RootClassId()
        {
            return "blog-view";
        }

        protected override void ShowView()
        {
            ShowPostsByCategory();
        }

        private void ShowPostsByCategory()
        {
            var start = Bloget.QueryStart;
            var category = Bloget.QueryCategory;

            ShowHeader(Bloget);

            // Ask for one more than we need. If we get it, we're not at the end of the list.
            var count = Bloget.Blog.PostsPerPage + 1;

            foreach (var post in Bloget.Blog.EnumeratePosts(start, count, category, false, false))
            {
                if (--count == 0)
                {
                    break;
                }

                ShowPost(post);
                ShowPostSeparator(post);
            }

            // Previous/Next Navigators
            var previousLink = string.Empty;

            if (start > 0)
            {
                var previousStart = Math.Max(start - Bloget.Blog.PostsPerPage, 0);
                previousLink = Bloget.BuildQueryString(Mode.Blog, null, previousStart, category, null, DateTime.MinValue, null);
            }

            var nextLink = string.Empty;

            if (count == 0)
            {
                var nextStart = Math.Min(start + Bloget.Blog.PostsPerPage, Bloget.Blog.Posts.Count - 1);
                nextLink = Bloget.BuildQueryString(Mode.Blog, null, nextStart, category, null, DateTime.MinValue, null);
            }

            ShowNavigators(Bloget, previousLink, nextLink);
            ShowFooter(Bloget);
            Bloget.PoweredByBloget();
        }

        internal void ShowPostsByMonth()
        {
            var start = Bloget.QueryStart;
            var monthYear = Bloget.QueryDate;

            ShowHeader(Bloget);

            // Ask for one more than we need. If we get it, we're not at the end of the list.
            var count = Bloget.Blog.PostsPerPage + 1;

            foreach (var post in Bloget.Blog.EnumeratePostsByMonth(start, count, monthYear))
            {
                if (--count == 0)
                {
                    break;
                }

                ShowPost(post);
                ShowPostSeparator(post);
            }

            var previousLink = string.Empty;

            if (start > 0)
            {
                var previousStart = Math.Max(start - Bloget.Blog.PostsPerPage, 0);
                previousLink = Bloget.BuildQueryString(Mode.Blog, null, previousStart, null, null, monthYear, null);
            }

            var nextLink = string.Empty;

            if (count == 0)
            {
                var nextStart = Math.Min(start + Bloget.Blog.PostsPerPage, Bloget.Blog.Posts.Count - 1);
                nextLink = Bloget.BuildQueryString(Mode.Blog, null, nextStart, null, null, monthYear, null);
            }

            ShowNavigators(Bloget, previousLink, nextLink);
            ShowFooter(Bloget);
            Bloget.PoweredByBloget();
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        internal void ShowPost()
        {
            if (Bloget.Blog.EnableAutoPingBack)
            {
                Bloget.Page.Response.AddHeader("X-Pingback", Bloget.RpcServiceUrl() ?? "");
            }

            Post post;
            var postId = Bloget.QueryPost;

            if (string.IsNullOrEmpty(postId) == false)
            {
                try
                {
                    var id = new Guid(postId);
                    post = Bloget.Blog.Posts[id];
                }

                catch (Exception)
                {
                    Bloget.WriteLine("<p>Identifier \"" + postId + "\" invalid</p>");
                    return;
                }
            }

            else
            {
                Bloget.WriteLine("<p>Missing post identifier</p>");
                return;
            }

            Bloget.Page.Title += " - " + post.Title;

            ShowHeader(Bloget);
            ShowPostNavigators(post);
            ShowPost(post);
            ShowPostSeparator(post);
            ShowCommentHeader(post);
            ShowComments(post);
            ShowPingBackHeader(post);
            ShowPingBacks(post);
            ShowCommentRequest(post);
            ShowFooter(Bloget);

            Bloget.PoweredByBloget();
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void AddCommentClick(object sender, EventArgs ea)
        {
            if (Bloget.Page.IsValid == false)
            {
                return;
            }

            if (Bloget.Blog.AllowComments == false)
            {
                return;
            }

            if (Bloget.Page.Session[CommentThrottle] != null)
            {
                var throttle = (DateTime) Bloget.Page.Session[CommentThrottle];
                var elapsed = DateTime.Now - throttle;

                if (elapsed.TotalSeconds < 30)
                {
                    return;
                }
            }

            var id = new Guid(Bloget.Page.Request[Bloget.BlogPostParameter]);
            var post = Bloget.Blog.Posts[id];
            var comment = new Comment
            {
                Title = Bloget.Page.Server.HtmlEncode(_commentTitle.Text),
                Author = Bloget.Page.Server.HtmlEncode(_commentName.Text),
                Email = Bloget.Page.Server.HtmlEncode(_commentEmail.Text),
                Text = Bloget.Page.Server.HtmlEncode(_commentText.Text)
            };

            var content = Bloget.Blog.LoadContent(id);
            content = new Content(content); // Clone to protect readers

            if (content.Comments.Count < Bloget.Blog.MaximumCommentsPerPost)
            {
                var verified = comment.VerifyComment();

                if (verified)
                {
                    content.Comments.Add(comment);
                    Bloget.Blog.SaveContent(post.Id, content);
                    Log.NewComment(Bloget, post.Title, comment.Id);
                }

                else
                {
                    Log.RejectComment(Bloget, post.Title, comment.Text);
                }

                try
                {
                    if (Bloget.Blog.EmailComments)
                    {
                        var subject = string.Format(CultureInfo.CurrentCulture,
                                                    "Bloget Comment Alert - Posting {0} {1}", id, post.Title);

                        var status = verified ? "Posted" : "***** Not Posted (possible spam detected) *****";

                        var message = string.Format(CultureInfo.CurrentCulture,
                                                    "Blog: {0}{5}Title: {1}{5}Link: {2}{5}Status: {3}{5}{5}---------{5}{5}{4}",
                                                    Bloget.Blog.Title, post.Title, Bloget.Page.Request.Url, status, comment, Environment.NewLine);

                        Bloget.SendEmail(Bloget.Blog.EmailTo, subject, message);
                    }
                }

                catch (Exception ex)
                {
                    Log.Exception(Bloget, "AddCommentClick", ex);
                }

                Bloget.Page.Session[CommentThrottle] = DateTime.Now;
                Bloget.Redirect(Bloget.Page.Request.RawUrl);
            }
        }

        internal static void ShowHeader(Bloget bloget)
        {
            if (bloget != null && bloget.TitleTemplate != null)
            {
                var blogContainer = new BlogContainerControl(bloget, bloget.Blog);
                bloget.TitleTemplate.InstantiateIn(blogContainer);
                bloget.Controls.Add(blogContainer);
            }
        }

        private static void ShowNavigators(Bloget bloget, string previousLink, string nextLink)
        {
            if (bloget == null)
            {
                throw new ArgumentNullException("bloget");
            }
            // Previous/Next Navigators
            var previousHyperLink = new HyperLink
            {
                Text = "previous",
                NavigateUrl = previousLink,
                Enabled = !string.IsNullOrEmpty(previousLink)
            };

            var nextHyperLink = new HyperLink
            {
                Text = "next",
                NavigateUrl = nextLink,
                Enabled = !string.IsNullOrEmpty(nextLink)
            };

            bloget.WriteLine("<p>");
            bloget.Controls.Add(previousHyperLink);
            bloget.Write(" | ");
            bloget.Controls.Add(nextHyperLink);
            bloget.WriteLine("</p>");
        }

        internal static void ShowFooter(Bloget bloget)
        {
            if (bloget == null)
            {
                throw new ArgumentNullException("bloget");
            }
            if (bloget.FooterTemplate != null)
            {
                var blogContainer = new BlogContainerControl(bloget, bloget.Blog) {EnableViewState = false};
                bloget.FooterTemplate.InstantiateIn(blogContainer);
                bloget.Controls.Add(blogContainer);
            }
        }

        private void ShowPostNavigators(Post post)
        {
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            Bloget.WriteLine("<p style=\"text-align:center\">&laquo;&nbsp;");

            var previousPost = Bloget.Blog.Posts.Previous(post.Id);

            if (previousPost != null)
            {
                var link = new HyperLink
                {
                    Text = Elipsis(previousPost.Title),
                    NavigateUrl = Bloget.BuildQueryString(Mode.Post, previousPost, 0, null, null, DateTime.MinValue, null)
                };
                link.Attributes.Add("rel", "nofollow");
                Bloget.Controls.Add(link);
            }

            Bloget.WriteLine(" | ");

            var nextPost = Bloget.Blog.Posts.Next(post.Id);

            if (nextPost != null)
            {
                var link = new HyperLink
                {
                    Text = Elipsis(nextPost.Title),
                    NavigateUrl = Bloget.BuildQueryString(Mode.Post, nextPost, 0, null, null, DateTime.MinValue, null)
                };
                link.Attributes.Add("rel", "nofollow");
                Bloget.Controls.Add(link);
            }

            Bloget.WriteLine("&nbsp;&raquo;</p>");
        }

        private void ShowPost(Post post)
        {
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            var content = Bloget.Blog.LoadContent(post.Id);

            if (Bloget.PostTemplate != null)
            {
                var postContainer = new PostContainerControl(Bloget, Bloget.Blog, post, content);
                Bloget.PostTemplate.InstantiateIn(postContainer);
                Bloget.Controls.Add(postContainer);
            }

            else
            {
                Bloget.WriteLine(@"<div class=""post"">");
                Bloget.WriteLine(@"<h3 class=""post-title"">");
                var link = new HyperLink
                {
                    NavigateUrl = Bloget.BuildQueryString(Mode.Post, post, 0, null, null, DateTime.MinValue, null), Text = post.Title
                };
                Bloget.Controls.Add(link);
                Bloget.WriteLine("</h3>");

                if (string.IsNullOrEmpty(post.Author) == false)
                {
                    Bloget.WriteLine(@"<span class=""post-author"">by " +
                        Bloget.Page.Server.HtmlEncode(post.Author) +
                            "</span><br/>");
                }

                Bloget.WriteLine(@"<span class=""post-date"">");
                var created = Time.LocalTime(Bloget.Blog.TimeZone, post.Created);
                Bloget.WriteLine(created.ToString("D", CultureInfo.CurrentCulture) + "</span><br/>");
                var firstTag = true;

                foreach (var tagInt in post.Tags)
                {
                    if (Bloget.Blog.Categories.Contains(tagInt))
                    {
                        Bloget.WriteLine(firstTag ? "<span>" : ", ");
                        firstTag = false;

                        var category = Bloget.Blog.Categories[tagInt];
                        var hyperLink = new HyperLink
                        {
                            Text = category.Name,
                            NavigateUrl = Bloget.BuildQueryString(Mode.Blog, null, 0, category, null, DateTime.MinValue, null)
                        };

                        Bloget.Controls.Add(hyperLink);
                    }
                }

                if (firstTag == false)
                {
                    Bloget.WriteLine("</span><br/>");
                }

                Bloget.WriteLine("<br/>");
                Bloget.WriteLine(@"<div class=""post-content"">");
                Bloget.WriteLine(content.Text);
                Bloget.WriteLine(@"</div><div class=""post-footer"">");

                if (Bloget.IsLoggedIn)
                {
                    var editLink = new HyperLink
                    {
                        NavigateUrl = Bloget.BuildQueryString(Mode.Edit, post, 0, null, null, DateTime.MinValue, null)
                    };
                    editLink.Attributes.Add("rel", "nofollow");
                    editLink.Text = "edit";
                    Bloget.Controls.Add(editLink);
                    Bloget.WriteLine("&nbsp;|&nbsp;");
                }

                var commentsLink = new HyperLink
                {
                    NavigateUrl = Bloget.BuildQueryString(Mode.Post, post, 0, null, null, DateTime.MinValue, null)
                };
                commentsLink.Attributes.Add("rel", "nofollow");
                commentsLink.Text = string.Format(CultureInfo.CurrentCulture, "comments ({0})", content.Comments.Count);
                Bloget.Controls.Add(commentsLink);

                if (content.Attachments.Count > 0)
                {
                    Bloget.WriteLine("<br />");
                    var enclosureLink = new HyperLink();
                    var enclosure = content.Attachments[0];
                    enclosureLink.NavigateUrl = enclosure.Url;
                    enclosureLink.Text = enclosure.ToString();
                    Bloget.Controls.Add(enclosureLink);
                }

                var relatedLinks = Bloget.RelatedPosts(post, 3);

                if (relatedLinks.Length > 0)
                {
                    Bloget.WriteLine("<p class=\"post-related\"><span>Related:</span></p><ul>");

                    foreach (var related in relatedLinks)
                    {
                        if (related != null)
                        {
                            Bloget.Write("<li>");
                            Bloget.Controls.Add(related);
                            Bloget.WriteLine("</li>");
                        }
                    }

                    Bloget.WriteLine("</ul>");
                }
                Bloget.WriteLine("</div></div>");
            }
        }

        private void ShowPostSeparator(Post post)
        {
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            if (Bloget.PostSeparatorTemplate != null)
            {
                var content = Bloget.Blog.LoadContent(post.Id);
                var postContainer = new PostContainerControl(Bloget, Bloget.Blog, post, content)
                {
                    EnableViewState = false
                };
                Bloget.PostSeparatorTemplate.InstantiateIn(postContainer);
                Bloget.Controls.Add(postContainer);
            }

            else
            {
                Bloget.WriteLine("<hr/>");
            }
        }

        private void ShowCommentHeader(Post post)
        {
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            var content = Bloget.Blog.LoadContent(post.Id);

            if (content.Comments.Count > 0)
            {
                if (Bloget.CommentHeaderTemplate != null)
                {
                    var postContainer = new PostContainerControl(Bloget, Bloget.Blog, post, content)
                    {
                        EnableViewState = false
                    };
                    Bloget.CommentHeaderTemplate.InstantiateIn(postContainer);
                    Bloget.Controls.Add(postContainer);
                }

                else
                {
                    Bloget.WriteLine("<p style=\"font-size:large; font-weight:bold\">Comments</p>");
                }
            }
        }

        private void ShowComments(Post post)
        {
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            var content = Bloget.Blog.LoadContent(post.Id);

            foreach (var comment in content.Comments)
            {
                if (Bloget.CommentTemplate != null)
                {
                    var commentContainer = new CommentContainerControl(Bloget, Bloget.Blog, post, content, comment)
                    {
                        EnableViewState = false
                    };
                    Bloget.CommentTemplate.InstantiateIn(commentContainer);
                    Bloget.Controls.Add(commentContainer);
                }

                else
                {
                    Bloget.WriteLine("<p><b>" + comment.Title + "</b><br/>");
                    Bloget.WriteLine("by " + comment.Author + "<br/>");
                    var created = Time.LocalTime(Bloget.Blog.TimeZone, comment.Date);
                    Bloget.WriteLine(created.ToString("f", CultureInfo.CurrentCulture));
                    Bloget.WriteLine("</p>");
                    Bloget.WriteLine("<div>");
                    Bloget.WriteLine(CommentToHtml(comment.Text));
                    Bloget.WriteLine("</div>");
                    Bloget.WriteLine("<hr/>");
                }

                if (Bloget.IsLoggedIn)
                {
                    Bloget.WriteLine("<p>");
                    var remove = new ConfirmedButton
                    {
                        ID = "C" + comment.Id,
                        Text = "Delete"
                    };
                    remove.Style.Add(HtmlTextWriterStyle.Color, "red");
                    remove.Message = "Remove this comment permanently?";
                    remove.Click += RemoveCommentClick;
                    Bloget.Controls.Add(remove);
                    Bloget.WriteLine("</p>");
                }
            }
        }

        private bool CommentPeriodExpired(Post post)
        {
            if (post == null || Bloget.Blog.ExpireComments < 1)
            {
                return false;
            }
            return post.Created.AddDays(Bloget.Blog.ExpireComments) < DateTime.UtcNow;
        }

        private void ShowPingBackHeader(Post post)
        {
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            var content = Bloget.Blog.LoadContent(post.Id);

            if (content.References.Count == 0)
            {
                return;
            }

            if (Bloget.PingBackHeaderTemplate != null)
            {
                var postContainer = new PostContainerControl(Bloget, Bloget.Blog, post, content) {EnableViewState = false};
                Bloget.PingBackHeaderTemplate.InstantiateIn(postContainer);
                Bloget.Controls.Add(postContainer);
            }

            else
            {
                Bloget.WriteLine("<p style=\"font-size:large; font-weight:bold\">Pingbacks</p>");
            }
        }

        private void ShowPingBacks(Post post)
        {
            if (post == null)
            {
                return;
            }
            var content = Bloget.Blog.LoadContent(post.Id);

            if (content.References.Count <= 0)
            {
                return;
            }

            foreach (var pingBack in content.References)
            {
                if (Bloget.PingBackTemplate != null)
                {
                    var pingBackContainer = new PingBackContainerControl(Bloget, Bloget.Blog, post, content, pingBack)
                    {
                        EnableViewState = false
                    };
                    Bloget.PingBackTemplate.InstantiateIn(pingBackContainer);
                    Bloget.Controls.Add(pingBackContainer);
                }

                else
                {
                    Bloget.WriteLine("<p>");
                    var created = Time.LocalTime(Bloget.Blog.TimeZone, pingBack.Date);
                    Bloget.WriteLine(created.ToString("f", CultureInfo.CurrentCulture));
                    Bloget.Write("&nbsp;&nbsp;");
                    var link = new HyperLink
                    {
                        NavigateUrl = pingBack.Link,
                        Text = pingBack.Link
                    };
                    Bloget.Controls.Add(link);
                    Bloget.WriteLine("</p>");
                }

                if (Bloget.IsLoggedIn)
                {
                    Bloget.WriteLine("<p>");
                    var remove = new ConfirmedButton
                    {
                        ID = "P" + pingBack.Id,
                        Text = "Delete"
                    };
                    remove.Style.Add(HtmlTextWriterStyle.Color, "red");
                    remove.Message = "Remove this pingback permanently?";
                    remove.Click += RemovePingBackClick;
                    Bloget.Controls.Add(remove);
                    Bloget.WriteLine("</p>");
                }
            }

            Bloget.WriteLine("<hr/>");
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void RemoveCommentClick(object sender, EventArgs ea)
        {
            var button = sender as ConfirmedButton;

            if (button != null)
            {
                try
                {
                    var commentId = new Guid(button.ID.Substring(1));

                    if (string.IsNullOrEmpty(Bloget.QueryPost) == false)
                    {
                        var id = new Guid(Bloget.QueryPost);
                        var post = Bloget.Blog.Posts[id];
                        var content = Bloget.Blog.LoadContent(id);
                        content = new Content(content); // Clone to protect readers

                        if (content.Comments.Contains(commentId))
                        {
                            content.Comments.Remove(commentId);
                            Bloget.Blog.SaveContent(id, content);
                            Log.RemoveComment(Bloget, post.Title, commentId);
                        }
                    }
                }

                catch (Exception ex)
                {
                    Bloget.ErrorPage(ex.ToString());
                    return;
                }

                Bloget.Redirect(Bloget.Page.Request.RawUrl);
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private void RemovePingBackClick(object sender, EventArgs ea)
        {
            var button = sender as ConfirmedButton;

            if (button != null)
            {
                try
                {
                    var pingBackId = new Guid(button.ID.Substring(1));

                    if (string.IsNullOrEmpty(Bloget.QueryPost) == false)
                    {
                        var id = new Guid(Bloget.QueryPost);
                        var content = Bloget.Blog.LoadContent(id);
                        content = new Content(content); // Clone to protect readers

                        if (content.References.Contains(pingBackId))
                        {
                            content.References.Remove(pingBackId);
                            Bloget.Blog.SaveContent(id, content);
                            Log.RemovePingBack(Bloget, id, pingBackId);
                        }
                    }
                }

                catch (Exception ex)
                {
                    Bloget.ErrorPage(ex.ToString());
                    return;
                }

                Bloget.Redirect(Bloget.Page.Request.RawUrl);
            }
        }

        private void ShowCommentRequest(Post post)
        {
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            var content = Bloget.Blog.LoadContent(post.Id);

            if (Bloget.Blog.AllowComments &&
                post.EnableComments &&
                    CommentPeriodExpired(post) == false &&
                        content.Comments.Count < Bloget.Blog.MaximumCommentsPerPost)
            {
                Bloget.WriteLine("<p><strong>Leave a Comment</strong></p>");
                InputField("Title", _commentTitle, "RE: " + post.Title, "The title of your comment", true, null);
                InputField("Name", _commentName, string.Empty, "Your real name please", true, null);
                InputField("Email", _commentEmail, string.Empty, "Email is not shown", true, AdminView.EmailValidator());

                Bloget.WriteLine("<p>Comments:");
                var rfv = new RequiredFieldValidator
                {
                    ControlToValidate = _commentText.ID,
                    EnableClientScript = false,
                    Text = " *"
                };
                Bloget.Controls.Add(rfv);
                Bloget.WriteLine("<br/>");

                _commentText.Style.Add(HtmlTextWriterStyle.Width, "90%");
                _commentText.MaxLength = 0x100000;
                _commentText.Wrap = true;
                _commentText.Rows = 12;
                _commentText.TextMode = TextBoxMode.MultiLine;
                Bloget.Controls.Add(_commentText);
                Bloget.WriteLine("</p>");

                var submit = new ConfirmedButton {Text = "Add Comment"};
                submit.Click += AddCommentClick;
                submit.Message = "Add Comment?";
                Bloget.Controls.Add(submit);
            }

            else
            {
                Bloget.WriteLine("<p>Comments closed</p>");
            }
        }

        internal static string CommentToHtml(string comment)
        {
            if (comment == null)
            {
                throw new ArgumentNullException("comment");
            }
            var delimiters = new[] {"\n\n"};
            var strings = comment.Split(delimiters, StringSplitOptions.None);
            var builder = new StringBuilder();

            foreach (var s in strings)
            {
                builder.Append("<p>");
                builder.Append(s);
                builder.Append("</p>");
            }

            var result = builder.ToString();
            return result.Replace("\n", "<br/>");
        }

        private static string Elipsis(string source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (source.Length < 25)
            {
                return source;
            }

            return string.Format(CultureInfo.CurrentCulture, "{0}...", source.Substring(0, 25));
        }

        private void InputField(string textLabel,
                                TextBox textBox,
                                string text,
                                string tooltip,
                                bool required,
                                BaseValidator validator)
        {
            if (textBox == null)
            {
                throw new ArgumentNullException("textBox");
            }
            textBox.TextMode = TextBoxMode.SingleLine;
            textBox.MaxLength = 100;
            textBox.Style.Add(HtmlTextWriterStyle.Width, "25em");
            Input(textLabel, textBox, text, tooltip, required, validator);
        }

        private void Input(string textLabel,
                           TextBox textBox,
                           string text,
                           string tooltip,
                           bool required,
                           BaseValidator validator)
        {
            if (textBox == null)
            {
                throw new ArgumentException("textBox");
            }
            Label(textLabel, textBox.ID);
            textBox.Text = text ?? string.Empty;
            textBox.ToolTip = tooltip ?? string.Empty;
            Bloget.Controls.Add(textBox);

            if (required)
            {
                var rfv = new RequiredFieldValidator
                {
                    ControlToValidate = textBox.ID,
                    EnableClientScript = false, Text = " *"
                };
                Bloget.Controls.Add(rfv);
            }

            if (validator != null)
            {
                validator.ControlToValidate = textBox.ID;
                Bloget.Controls.Add(validator);
            }

            Bloget.WriteLine("<br />");
        }
    }
}